home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 001 / fue / c / WORD < prev   
Text File  |  1991-04-03  |  18KB  |  731 lines

  1. /*
  2.  * The routines in this file implement commands that work word or a
  3.  * paragraph at a time.  There are all sorts of word mode commands.  If I
  4.  * do any sentence mode commands, they are likely to be put in this file. 
  5.  */
  6.  
  7. #include    <stdio.h>
  8. #include    "estruct.h"
  9. #include    "etype.h"
  10. #include    "edef.h"
  11. #include    "elang.h"
  12.  
  13. /* Word wrap on n-spaces. Back-over whatever precedes the point on the current
  14.  * line and stop on the first word-break or the beginning of the line. If we
  15.  * reach the beginning of the line, jump back to the end of the word and start
  16.  * a new line.    Otherwise, break the line at the word-break, eat it, and jump
  17.  * back to the end of the word. Make sure we force the display back to the
  18.  * left edge of the current window
  19.  * Returns TRUE on success, FALSE on errors.
  20.  */
  21. PASCAL NEAR wrapword(f, n)
  22.  
  23. int f;        /* default flag */
  24. int n;        /* numeric argument */
  25.  
  26. {
  27.     register int cnt;    /* size of word wrapped to next line */
  28.     register int c;        /* charector temporary */
  29.  
  30.     /* backup from the <NL> 1 char */
  31.     if (!backchar(FALSE, 1))
  32.         return(FALSE);
  33.  
  34.     /* back up until we aren't in a word,
  35.        make sure there is a break in the line */
  36.     cnt = 0;
  37.     while (((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ')
  38.                 && (c != '\t')) {
  39.         cnt++;
  40.         if (!backchar(FALSE, 1))
  41.             return(FALSE);
  42.         /* if we make it to the beginning, start a new line */
  43.         if (curwp->w_doto == 0) {
  44.             gotoeol(FALSE, 0);
  45.             return(lnewline());
  46.         }
  47.     }
  48.  
  49.     /* delete the forward white space */
  50.     if (!forwdel(0, 1))
  51.         return(FALSE);
  52.  
  53.     /* put in a end of line */
  54.     if (!lnewline())
  55.         return(FALSE);
  56.  
  57.     /* and past the first word */
  58.     while (cnt-- > 0) {
  59.         if (forwchar(FALSE, 1) == FALSE)
  60.             return(FALSE);
  61.     }
  62.  
  63.     /* make sure the display is not horizontally scrolled */
  64.     if (curwp->w_fcol != 0) {
  65.         curwp->w_fcol = 0;
  66.         curwp->w_flag |= WFHARD | WFMOVE | WFMODE;
  67.     }
  68.  
  69.     return(TRUE);
  70. }
  71.  
  72. /*
  73.  * Move the cursor backward by "n" words. All of the details of motion are
  74.  * performed by the "backchar" and "forwchar" routines. Error if you try to
  75.  * move beyond the buffers.
  76.  */
  77. PASCAL NEAR backword(f, n)
  78. {
  79.     if (n < 0)
  80.         return(forwword(f, -n));
  81.     if (backchar(FALSE, 1) == FALSE)
  82.         return(FALSE);
  83.     while (n--) {
  84.         while (inword() == FALSE) {
  85.             if (backchar(FALSE, 1) == FALSE)
  86.                 return(FALSE);
  87.         }
  88.         while (inword() != FALSE) {
  89.             if (backchar(FALSE, 1) == FALSE)
  90.                 return(FALSE);
  91.         }
  92.     }
  93.     return(forwchar(FALSE, 1));
  94. }
  95.  
  96. /*
  97.  * Move the cursor forward by the specified number of words. All of the motion
  98.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  99.  */
  100. PASCAL NEAR forwword(f, n)
  101. {
  102.     if (n < 0)
  103.         return(backword(f, -n));
  104.     while (n--) {
  105.         /* scan through the current word */
  106.         while (inword() == TRUE) {
  107.             if (forwchar(FALSE, 1) == FALSE)
  108.                 return(FALSE);
  109.         }
  110.  
  111.         /* scan through the intervening white space */
  112.         while (inword() == FALSE) {
  113.             if (forwchar(FALSE, 1) == FALSE)
  114.                 return(FALSE);
  115.         }
  116.     }
  117.     return(TRUE);
  118. }
  119.  
  120. /*
  121.  * Move forward to the end of the nth next word. Error if you move past
  122.  * the end of the buffer.
  123.  */
  124. PASCAL NEAR endword(f, n)
  125. {
  126.     if (n < 0)
  127.         return(backword(f, -n));
  128.     while (n--) {
  129.         /* scan through the intervening white space */
  130.         while (inword() == FALSE) {
  131.             if (forwchar(FALSE, 1) == FALSE)
  132.                 return(FALSE);
  133.         }
  134.  
  135.         /* scan through the current word */
  136.         while (inword() == TRUE) {
  137.             if (forwchar(FALSE, 1) == FALSE)
  138.                 return(FALSE);
  139.         }
  140.     }
  141.     return(TRUE);
  142. }
  143.  
  144. /*
  145.  * Move the cursor forward by the specified number of words. As you move,
  146.  * convert any characters to upper case. Error if you try and move beyond the
  147.  * end of the buffer. Bound to "M-U".
  148.  */
  149. PASCAL NEAR upperword(f, n)
  150. {
  151.     int c;
  152.  
  153.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  154.         return(rdonly());    /* we are in read only mode    */
  155.     if (n < 0)
  156.         return(FALSE);
  157.     while (n--) {
  158.         while (inword() == FALSE) {
  159.             if (forwchar(FALSE, 1) == FALSE)
  160.                 return(FALSE);
  161.         }
  162.         while (inword() != FALSE) {
  163.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  164.             if (islower(c)) {
  165.                 c = upperc(c);
  166.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  167.                 lchange(WFHARD);
  168.             }
  169.             if (forwchar(FALSE, 1) == FALSE)
  170.                 return(FALSE);
  171.         }
  172.     }
  173.     return(TRUE);
  174. }
  175.  
  176. /*
  177.  * Move the cursor forward by the specified number of words. As you move
  178.  * convert characters to lower case. Error if you try and move over the end of
  179.  * the buffer. Bound to "M-L".
  180.  */
  181. PASCAL NEAR lowerword(f, n)
  182. {
  183.     int c;
  184.  
  185.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  186.         return(rdonly());    /* we are in read only mode    */
  187.     if (n < 0)
  188.         return(FALSE);
  189.     while (n--) {
  190.         while (inword() == FALSE) {
  191.             if (forwchar(FALSE, 1) == FALSE)
  192.                 return(FALSE);
  193.         }
  194.         while (inword() != FALSE) {
  195.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  196.             if (isupper(c)) {
  197.                 c = lowerc(c);
  198.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  199.                 lchange(WFHARD);
  200.             }
  201.             if (forwchar(FALSE, 1) == FALSE)
  202.                 return(FALSE);
  203.         }
  204.     }
  205.     return(TRUE);
  206. }
  207.  
  208. /*
  209.  * Move the cursor forward by the specified number of words. As you move
  210.  * convert the first character of the word to upper case, and subsequent
  211.  * characters to lower case. Error if you try and move past the end of the
  212.  * buffer. Bound to "M-C".
  213.  */
  214. PASCAL NEAR capword(f, n)
  215. {
  216.     int c;
  217.  
  218.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  219.         return(rdonly());    /* we are in read only mode    */
  220.     if (n < 0)
  221.         return(FALSE);
  222.     while (n--) {
  223.         while (inword() == FALSE) {
  224.             if (forwchar(FALSE, 1) == FALSE)
  225.                 return(FALSE);
  226.         }
  227.         if (inword() != FALSE) {
  228.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  229.             if (islower(c)) {
  230.                 c = upperc(c);
  231.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  232.                 lchange(WFHARD);
  233.             }
  234.             if (forwchar(FALSE, 1) == FALSE)
  235.                 return(FALSE);
  236.             while (inword() != FALSE) {
  237.                 c = lgetc(curwp->w_dotp, curwp->w_doto);
  238.                 if (isupper(c)) {
  239.                     c = lowerc(c);
  240.                     lputc(curwp->w_dotp, curwp->w_doto, c);
  241.                     lchange(WFHARD);
  242.                 }
  243.                 if (forwchar(FALSE, 1) == FALSE)
  244.                     return(FALSE);
  245.             }
  246.         }
  247.     }
  248.     return(TRUE);
  249. }
  250.  
  251.  
  252. PASCAL NEAR fwdchar(f, n)
  253. /* A special version of forwchar that won't move off a fold line,
  254.  * required for delfword.
  255.  */
  256. register int    n;
  257. {
  258.         if (n < 0)
  259.                 return(FALSE);
  260.         while (n--) {
  261.                 if (curwp->w_doto == llength(curwp->w_dotp)) {
  262.                         if ((curwp->w_dotp == curbp->b_linep) ||
  263.                             (curwp->w_dotp->l_type != LNORMAL) ||
  264.                             (curwp->w_dotp->l_fp->l_type != LNORMAL))
  265.                                 return(FALSE);
  266.                         curwp->w_dotp  = lforw(curwp->w_dotp);
  267.                         curwp->w_doto  = 0;
  268.                         curwp->w_flag |= WFMOVE;
  269.                 } else
  270.                         curwp->w_doto++;
  271.         }
  272.         return(TRUE);
  273. }
  274.  
  275.  
  276. /*
  277.  * Kill forward by "n" words. Remember the location of dot. Move forward by
  278.  * the right number of words. Put dot back where it was and issue the kill
  279.  * command for the right number of characters. With a zero argument, just
  280.  * kill one word and no whitespace. Bound to "M-D".
  281.  *
  282.  * Due to folds I changed this to use a kill-region instead of ldelete.
  283.  * MJB: 05-Sep-90.
  284.  */
  285. PASCAL NEAR delfword(f, n)
  286. {
  287.     register LINE    *dotp, *markp;    /* original cursor line */
  288.     register int    doto, marko;    /*    and row */
  289.     register int c, s;        /* temp char */
  290.  
  291.     /* don't allow this command if we are in read only mode */
  292.     if (curbp->b_mode&MDVIEW)
  293.         return(rdonly());
  294.  
  295.     /* ignore the command if there is a negative argument */
  296.     if (n < 0)
  297.         return(FALSE);
  298.  
  299.     /* Clear the kill buffer if last command wasn't a kill */
  300.     if ((lastflag&CFKILL) == 0)
  301.         kdelete();
  302.     thisflag |= CFKILL;    /* this command is a kill */
  303.  
  304.     /* save the current cursor position */
  305.     dotp = curwp->w_dotp;
  306.     doto = curwp->w_doto;
  307.  
  308.     /* get us into a word.... */
  309.     while (inword() == FALSE) {
  310.         if (fwdchar(FALSE, 1) == FALSE)
  311.             return(FALSE);
  312.     }
  313.  
  314.     if (n == 0) {
  315.         /* skip one word, no whitespace! */
  316.         while (inword() == TRUE) {
  317.             if (fwdchar(FALSE, 1) == FALSE)
  318.                 return(FALSE);
  319.         }
  320.     } else {
  321.         /* skip n words.... */
  322.         while (n--) {
  323.     
  324.             /* if we are at EOL; skip to the beginning of the next */
  325.             while (curwp->w_doto == llength(curwp->w_dotp)) {
  326.                 if (fwdchar(FALSE, 1) == FALSE)
  327.                     return(FALSE);
  328.             }
  329.     
  330.             /* move forward till we are at the end of the word */
  331.             while (inword() == TRUE) {
  332.                 if (fwdchar(FALSE, 1) == FALSE)
  333.                     return(FALSE);
  334.             }
  335.     
  336.             /* if there are more words, skip the interword stuff */
  337.             if (n != 0)
  338.                 while (inword() == FALSE) {
  339.                     if (fwdchar(FALSE, 1) == FALSE)
  340.                         return(FALSE);
  341.                 }
  342.         }
  343.     
  344.         /* skip whitespace and newlines */
  345.         /* this is bad news if folds are about */
  346.          while (
  347.                        ((curwp->w_dotp->l_fp->l_type == LNORMAL) &&
  348.             (curwp->w_doto == llength(curwp->w_dotp))) ||
  349.                        ((curwp->w_doto < llength(curwp->w_dotp)) &&
  350.             (((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ') ||
  351.              (c == '\t')))
  352.               ) {
  353.                 if (fwdchar(FALSE, 1) == FALSE)
  354.                     return(FALSE);
  355.         }
  356.     }
  357.  
  358.     /* restore the original position and delete the words */
  359.     markp = curwp->w_markp[0];
  360.     marko = curwp->w_marko[0];
  361.         curwp->w_markp[0] = curwp->w_dotp;
  362.     curwp->w_marko[0] = curwp->w_doto;
  363.     curwp->w_dotp = dotp;
  364.     curwp->w_doto = doto;
  365.     s = killregion(FALSE, 0);
  366.     curwp->w_markp[0] = markp;
  367.     curwp->w_marko[0] = marko;
  368.     return(s);
  369. }
  370.  
  371. /*
  372.  * Kill backwards by "n" words. Move backwards by the desired number of words,
  373.  * counting the characters. When dot is finally moved to its resting place,
  374.  * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
  375.  */
  376. PASCAL NEAR delbword(f, n)
  377. {
  378.     long size;
  379.  
  380.     /* don't allow this command if we are in read only mode */
  381.     if (curbp->b_mode&MDVIEW)
  382.         return(rdonly());
  383.  
  384.     /* ignore the command if there is a nonpositive argument */
  385.     if (n <= 0)
  386.         return(FALSE);
  387.  
  388.     /* Clear the kill buffer if last command wasn't a kill */
  389.     if ((lastflag&CFKILL) == 0)
  390.         kdelete();
  391.     thisflag |= CFKILL;    /* this command is a kill */
  392.  
  393.     if (backchar(FALSE, 1) == FALSE)
  394.         return(FALSE);
  395.     size = 0;
  396.     while (n--) {
  397.         while (inword() == FALSE) {
  398.             if (backchar(FALSE, 1) == FALSE)
  399.                 return(FALSE);
  400.             ++size;
  401.         }
  402.         while (inword() != FALSE) {
  403.             ++size;
  404.             if (backchar(FALSE, 1) == FALSE)
  405.                 goto bckdel;
  406.         }
  407.     }
  408.     if (forwchar(FALSE, 1) == FALSE)
  409.         return(FALSE);
  410. bckdel:    return(ldelete(size, TRUE, FALSE, TRUE));
  411. }
  412.  
  413. /*
  414.  * Return TRUE if the character at dot is a character that is considered to be
  415.  * part of a word. The word character list is hard coded. Should be setable.
  416.  */
  417. PASCAL NEAR inword()
  418. {
  419.     register int    c;
  420.  
  421.     if (curwp->w_doto == llength(curwp->w_dotp))
  422.         return(FALSE);
  423.     c = lgetc(curwp->w_dotp, curwp->w_doto);
  424.     if (isletter(c))
  425.         return(TRUE);
  426.     if (c>='0' && c<='9')
  427.         return(TRUE);
  428.     return(FALSE);
  429. }
  430.  
  431. #if    WORDPRO
  432. PASCAL NEAR fillpara(f, n)    /* Fill the current paragraph according to the
  433.                current fill column */
  434.  
  435. int f, n;    /* Default flag and Numeric argument */
  436.  
  437. {
  438.     register char *pp;    /* ptr into paragraph being reformed */
  439.     register char *para;    /* malloced buffer for paragraph */
  440.     register LINE *lp;    /* ptr to current line */
  441.     register int lsize;    /* bytes in current line */
  442.     register char *txtptr;    /* ptr into current line */
  443.     LINE *ptline;        /* line the point started on */
  444.     int ptoff;        /* offset of original point */
  445.     int back;        /* # of characters from origin point to eop */
  446.     int status;        /* return status from linstr() */
  447.     int psize;        /* byte size of paragraph */
  448.     LINE *bop;        /* ptr to beg of paragraph */
  449.     LINE *eop;        /* pointer to line just past EOP */
  450.  
  451.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  452.         return(rdonly());    /* we are in read only mode    */
  453.     if (fillcol == 0) {    /* no fill column set */
  454.         mlwrite(TEXT98);
  455. /*                      "No fill column set" */
  456.         return(FALSE);
  457.     }
  458.  
  459.     /* save the original point */
  460.     ptline = curwp->w_dotp;
  461.     ptoff = curwp->w_doto;
  462.  
  463.     /* record the pointer to the line just past the EOP */
  464.     gotoeop(FALSE, 1);
  465.  
  466.     /* Make sure we aren't on a fold line. MJB: 04-Oct-89 */
  467.     if (curwp->w_dotp->l_type != LNORMAL) {
  468.         curwp->w_dotp = lback(curwp->w_dotp);
  469.         curwp->w_doto = llength(curwp->w_dotp);
  470.         if (curwp->w_dotp->l_type != LNORMAL) {
  471.             curwp->w_dotp = ptline;
  472.             curwp->w_doto = ptoff;
  473.             return(FALSE);
  474.         }
  475.     }
  476.  
  477.     eop = lforw(curwp->w_dotp);
  478.  
  479.     /* and back top the beginning of the paragraph */
  480.     gotobop(FALSE, 1);
  481.  
  482.     /* Make sure we aren't on a fold line. MJB: 04-Oct-89 */
  483.     if (curwp->w_dotp->l_type != LNORMAL) {
  484.         curwp->w_dotp = lforw(curwp->w_dotp);
  485.         if (curwp->w_dotp->l_type != LNORMAL) {
  486.             curwp->w_dotp = ptline;
  487.             curwp->w_doto = ptoff;
  488.             return(FALSE);
  489.         }
  490.     }
  491.  
  492.     bop = lp = curwp->w_dotp;
  493.  
  494.     /* ok, how big is this paragraph? */
  495.     psize = 0;
  496.     while (lp != eop) {
  497.         psize += lp->l_used + 1;
  498.         lp = lp->l_fp;
  499.     }
  500.  
  501.     /* create a buffer to hold this stuff */
  502.     para = malloc(psize + 100);    /***** THIS IS TEMP *****/
  503.     if (para == NULL) {
  504.         mlwrite(TEXT99);
  505. /*                      "[OUT OF MEMORY]" */
  506.         return(FALSE);
  507.     }
  508.  
  509.     /* now, grab all the text into a string */
  510.     back = 0;    /* counting the distance to backup when done */
  511.     lp = bop;
  512.     pp = para;
  513.     while (lp != eop) {
  514.         lsize = lp->l_used;
  515.         if (back == 0) {
  516.             if (lp == ptline)
  517.                 back = lsize - ptoff + 1;
  518.         } else
  519.             back += lsize + 1;
  520.         txtptr = lp->l_text;
  521.         while (lsize--)            /* copy a line */
  522.             *pp++ = *txtptr++;
  523.         *pp++ = ' ';            /* turn the NL to a space */
  524.         lp = lp->l_fp;
  525.         lfree(lp->l_bp);        /* free the old line */
  526.     }
  527.     *(--pp) = 0;    /* truncate the last space */
  528.  
  529.     /* reformat the paragraph in the buffer */
  530.     reform(para);
  531.  
  532.     /* insert the reformatted paragraph back into the current buffer */
  533.     /* just in case we are at a foldline but newline in first & backup */
  534.     lnewline();
  535.     backchar(FALSE, 1);
  536.     status = linstr(para);
  537.     if (status == TRUE)    /* reposition us to the same place */
  538.         status = backchar(FALSE, back);
  539.  
  540.     /* make sure the display is not horizontally scrolled */
  541.     if (curwp->w_fcol != 0) {
  542.         curwp->w_fcol = 0;
  543.         curwp->w_flag |= WFHARD | WFMOVE | WFMODE;
  544.     }
  545.  
  546.     /* free the buffer and return */
  547.     free(para);
  548.     return(status);
  549. }
  550.  
  551. PASCAL NEAR reform(para)    /* reformat a paragraph as stored in a string */
  552.  
  553. char *para;    /* string buffer containing paragraph */
  554.  
  555. {
  556.     register char *sp;        /* string scan pointer */
  557.     register int col;        /* current colomn position */
  558.     register char *lastword;    /* ptr to end of last word */
  559.  
  560.     /* scan string, replacing some whitespace with newlines */
  561.     sp = para;
  562.     lastword = para;
  563.     col = 0;
  564.     while (*sp) {
  565.         /* if we are at white space.... */
  566.         if ((*sp == ' ') || (*sp == '\t')) {
  567.             if (*sp == '\t')
  568.                 col = (col + 8) & (~7);
  569.             else
  570.                 col++;
  571.  
  572.             /* break on whitespace? */
  573.             if (col >= fillcol) {
  574.                 *sp = '\r';
  575.                 col = 0;
  576.             }
  577.  
  578.             /* onward, resetting the most recent begin of word */
  579.             ++sp;
  580.             lastword = sp;
  581.  
  582.         } else {    /* a non-blank to process */
  583.  
  584.             ++sp;
  585.             ++col;
  586.             if (col >= fillcol) {
  587.                 /* line break here! */
  588.                 if ((lastword > para) &&
  589.                    (*(lastword - 1) != '\r')) {
  590.                        *(lastword - 1) = '\r';
  591.                        sp = lastword;
  592.                        col = 0;
  593.                 }
  594.             }
  595.         }
  596.     }
  597. }
  598.  
  599. PASCAL NEAR killpara(f, n)    /* delete n paragraphs starting with the current one */
  600.  
  601. int f;    /* default flag */
  602. int n;    /* # of paras to delete */
  603.  
  604. {
  605.     register int status;    /* returned status of functions */
  606.     LINE *ptline;        /* start line */
  607.     int  ptoff;        /* & offset */
  608.  
  609.     while (n--) {        /* for each paragraph to delete */
  610.  
  611.         /* save the original point */
  612.         ptline = curwp->w_dotp;
  613.         ptoff = curwp->w_doto;
  614.  
  615.         /* mark out the end and beginning of the para to delete */
  616.         gotoeop(FALSE, 1);
  617.  
  618.         /* Make sure we aren't on a fold line. MJB: 04-Oct-89 */
  619.         if (curwp->w_dotp->l_type != LNORMAL) {
  620.             curwp->w_dotp = lback(curwp->w_dotp);
  621.             curwp->w_doto = llength(curwp->w_dotp);
  622.             if (curwp->w_dotp->l_type != LNORMAL) {
  623.                 curwp->w_dotp = ptline;
  624.                 curwp->w_doto = ptoff;
  625.                 return(FALSE);
  626.             }
  627.         }
  628.  
  629.         /* set the mark here */
  630.         curwp->w_markp[0] = curwp->w_dotp;
  631.         curwp->w_marko[0] = curwp->w_doto;
  632.  
  633.         /* go to the beginning of the paragraph */
  634.         gotobop(FALSE, 1);
  635.         curwp->w_doto = 0;    /* force us to the beginning of line */
  636.  
  637.         /* Make sure we aren't on a fold line. MJB: 04-Oct-89 */
  638.         if (curwp->w_dotp->l_type != LNORMAL) {
  639.             curwp->w_dotp = lforw(curwp->w_dotp);
  640.             if (curwp->w_dotp->l_type != LNORMAL) {
  641.                 curwp->w_dotp = ptline;
  642.                 curwp->w_doto = ptoff;
  643.                 return(FALSE);
  644.             }
  645.         }
  646.  
  647.         /* and delete it */
  648.         if ((status = killregion(FALSE, 1)) != TRUE)
  649.             return(status);
  650.  
  651.         /* and clean up the 2? extra lines */
  652.         if ((curwp->w_dotp->l_type == LNORMAL) &&
  653.             (curwp->w_dotp->l_fp->l_type == LNORMAL))
  654.             ldelete(2L, TRUE, FALSE, FALSE);
  655.         else
  656.             ldelete(1L, TRUE, FALSE, FALSE);
  657.     }
  658.     return(TRUE);
  659. }
  660.  
  661.  
  662. /*    wordcount:    count the # of words in the marked region,
  663.             along with average word sizes, # of chars, etc,
  664.             and report on them.            */
  665.  
  666. PASCAL NEAR wordcount(f, n)
  667.  
  668. int f, n;    /* ignored numeric arguments */
  669.  
  670. {
  671.     register LINE *lp;    /* current line to scan */
  672.     register int offset;    /* current char to scan */
  673.     long size;        /* size of region left to count */
  674.     register int ch;    /* current character to scan */
  675.     register int wordflag;    /* are we in a word now? */
  676.     register int lastword;    /* were we just in a word? */
  677.     long nwords;        /* total # of words */
  678.     long nchars;        /* total number of chars */
  679.     int nlines;        /* total number of lines in region */
  680.     int avgch;        /* average number of chars/word */
  681.     int status;        /* status return code */
  682.     REGION region;        /* region to look at */
  683.  
  684.     /* make sure we have a region to count */
  685.     if ((status = getregion(®ion)) != TRUE)
  686.         return(status);
  687.     lp = region.r_linep;
  688.     offset = region.r_offset;
  689.     size = region.r_size;
  690.  
  691.     /* count up things */
  692.     lastword = FALSE;
  693.     nchars = 0L;
  694.     nwords = 0L;
  695.     nlines = 0;
  696.     while (size--) {
  697.  
  698.         /* get the current character */
  699.         if (offset == llength(lp)) {    /* end of line */
  700.             ch = '\r';
  701.             lp = lforw(lp);
  702.             offset = 0;
  703.             ++nlines;
  704.         } else {
  705.             ch = lgetc(lp, offset);
  706.             ++offset;
  707.         }
  708.  
  709.         /* and tabulate it */
  710.         wordflag = ((ch >= 'a' && ch <= 'z') ||
  711.                 (ch >= 'A' && ch <= 'Z') ||
  712.                 (ch >= '0' && ch <= '9'));
  713.         if (wordflag == TRUE && lastword == FALSE)
  714.             ++nwords;
  715.         lastword = wordflag;
  716.         ++nchars;
  717.     }
  718.  
  719.     /* and report on the info */
  720.     if (nwords > 0L)
  721.         avgch = (int)((100L * nchars) / nwords);
  722.     else
  723.         avgch = 0;
  724.  
  725.     mlwrite(TEXT100,
  726. /*              "Words %D Chars %D Lines %d Avg chars/word %f" */
  727.         nwords, nchars, nlines + 1, avgch);
  728.     return(TRUE);
  729. }
  730. #endif
  731.